<template>
	<view class="container">
		<view class="remote-control">
			<!-- 上按钮 -->
			<view class="control-btn up-btn" :class="{ active: btnActive.up }" @touchstart="handleTouchStart('up')" @touchend="handleTouchEnd('up')">上</view>

			<!-- 左右按钮和中间语音按钮 -->
			<view class="middle-row">
				<view class="control-btn left-btn" :class="{ active: btnActive.left }" @touchstart="handleTouchStart('left')" @touchend="handleTouchEnd('left')">左</view>

				<view class="voice-btn" @touchstart="startVoiceInput" @touchend="stopVoiceInput" @touchcancel="cancelRecording" :class="{ recording: isRecording }">
					<text v-if="!isRecording">语音</text>
					<text v-else class="recording-text">录制中...</text>
					<view class="voice-wave" v-if="isRecording">
						<view class="wave" v-for="(item, index) in waves" :key="index" :style="{ height: item + 'px' }"></view>
					</view>
				</view>

				<view class="control-btn right-btn" :class="{ active: btnActive.right }" @touchstart="handleTouchStart('right')" @touchend="handleTouchEnd('right')">右</view>
			</view>

			<!-- 下按钮 -->
			<view class="control-btn down-btn" :class="{ active: btnActive.down }" @touchstart="handleTouchStart('down')" @touchend="handleTouchEnd('down')">下</view>
		</view>

		<!-- 语音识别结果 -->
		<view class="voice-result" v-if="voiceResult">
			<text>识别结果: {{ voiceResult }}</text>
		</view>
	</view>
</template>

<script>
export default {
	name: 'RemoteControl',
	data() {
		return {
			recorderManager: null,
			audioPath: '',
			btnActive: {
				up: false,
				down: false,
				left: false,
				right: false
			},
			isRecording: false,
			voiceResult: '',
			waves: [],
			waveInterval: null,
			resUrl: '',
			processor: null,
			audioContext: null,
			audioStream: null,
			pcmChunks: [] // 存储PCM数据块
		};
	},
	mounted() {
		// 初始化录音管理器
		// #ifdef APP-PLUS
		this.recorderManager = uni.getRecorderManager();

		// 监听录音开始事件
		this.recorderManager.onStart(() => {
			console.log('录音开始');
			this.isRecording = true;
		});

		// 监听录音结束事件
		this.recorderManager.onStop((res) => {
			console.log('录音结束', res);
			this.isRecording = false;
			this.audioPath = res.tempFilePath;

			// 这里可以处理获取到的音频文件
			this.processAudioFile(res.tempFilePath);
		});
		// #endif
	},
	methods: {
		// 方向按钮按下效果
		handleTouchStart(direction) {
			this.btnActive[direction] = true;
			this.$emit('touchStart', direction);
		},

		// 方向按钮释放效果
		handleTouchEnd(direction) {
			this.btnActive[direction] = false;
			this.$emit('touchEnd', direction);
		},

		// 方向按钮点击事件
		handleDirectionClick(direction) {
			this.$emit('clickBtn', direction);
		},

		// 获取方向名称
		getDirectionName(direction) {
			const map = {
				up: '上',
				down: '下',
				left: '左',
				right: '右'
			};
			return map[direction];
		},

		// 开始语音输入
		async startVoiceInput(e) {
			try {
				// 1. 获取麦克风权限
				this.audioStream = await navigator.mediaDevices.getUserMedia({
					audio: {
						sampleRate: 8000, // 请求8000Hz采样率
						channelCount: 1 // 单声道
					}
				});

				// 2. 创建音频处理上下文
				this.audioContext = new (window.AudioContext || window.webkitAudioContext)({
					sampleRate: 8000 // 强制8000Hz采样率
				});

				const source = this.audioContext.createMediaStreamSource(this.audioStream);

				// 3. 创建PCM处理器
				this.processor = this.audioContext.createScriptProcessor(4096, 1, 1);
				this.pcmChunks = [];

				// 4. 配置音频处理回调
				this.processor.onaudioprocess = (event) => {
					const inputBuffer = event.inputBuffer;
					const channelData = inputBuffer.getChannelData(0);
					const pcmData = this.floatTo16BitPCM(channelData);
					this.pcmChunks.push(pcmData);
				};

				// 5. 连接处理节点
				source.connect(this.processor);
				this.processor.connect(this.audioContext.destination);
				this.isRecording = true;
			} catch (err) {
				console.error('录音启动失败:', err);
			}

			// #ifdef APP-PLUS
			this.isRecording = true;
			this.startWaveAnimation();

			//开始录音
			this.recorderManager.start({
				format: 'PCM', // 使用PCM格式获取原始数据
				sampleRate: 8000, // 8000Hz采样率
				numberOfChannels: 1, // 单通道
				encodeBitRate: 16, // 16位
				frameSize: 1024 // 帧大小
			});
			// #endif
		},

		// 停止语音输入
		async stopVoiceInput(e) {
			if (!this.isRecording) return;

			// 1. 断开音频节点
			this.processor.disconnect();
			this.audioContext.close();

			// 2. 停止媒体流
			this.audioStream.getTracks().forEach((track) => track.stop());

			// 3. 合并PCM数据
			const totalLength = this.pcmChunks.reduce((len, chunk) => len + chunk.length, 0);
			const mergedPCM = new Int16Array(totalLength);
			let offset = 0;

			this.pcmChunks.forEach((chunk) => {
				mergedPCM.set(chunk, offset);
				offset += chunk.length;
			});

			// 4. 转换为Base64
			const tempStr = this.arrayBufferToBase64(mergedPCM.buffer);
			const base64String = encodeURIComponent(tempStr);
			console.log('PCM Base64:', base64String.substring(0, 100) + '...');

			this.isRecording = false;
			this.$emit('getResUrl', base64String); // 触发事件

			// #ifdef APP-PLUS
			this.isRecording = false;
			this.stopWaveAnimation();
			this.recorderManager.stop();
			// #endif
		},

		// 音频数据转换核心方法
		floatTo16BitPCM(input) {
			const output = new Int16Array(input.length);
			for (let i = 0; i < input.length; i++) {
				const s = Math.max(-1, Math.min(1, input[i]));
				output[i] = s < 0 ? s * 0x8000 : s * 0x7fff;
			}
			return output;
		},

		arrayBufferToBase64(buffer) {
			let binary = '';
			const bytes = new Uint8Array(buffer);
			for (let i = 0; i < bytes.byteLength; i++) {
				binary += String.fromCharCode(bytes[i]);
			}
			return window.btoa(binary);
		},

		//取消录音输入
		cancelRecording() {
			console.log('取消');
		},

		// 处理音频文件
		processAudioFile(filePath) {
			console.log('音频文件路径:', filePath);
			plus.io.resolveLocalFileSystemURL(
				filePath,
				(entry) => {
					entry.file(
						(file) => {
							const reader = new plus.io.FileReader();
							reader.onloadend = (e) => {
								this.resUrl = encodeURIComponent(e.target.result);
								this.$emit('getResUrl', this.resUrl);
							};
							reader.readAsDataURL(file);
						},
						(err) => {
							console.error('App 读取文件失败:', err);
						}
					);
				},
				(err) => {
					console.error('App 解析文件失败:', err);
				}
			);
		},

		// 开始声波动画
		startWaveAnimation() {
			this.waves = [5, 10, 15, 10, 5];
			this.waveInterval = setInterval(() => {
				this.waves = this.waves.map(() => Math.floor(Math.random() * 15) + 5);
			}, 200);
		},

		// 停止声波动画
		stopWaveAnimation() {
			if (this.waveInterval) {
				clearInterval(this.waveInterval);
				this.waveInterval = null;
			}
			this.waves = [];
		}
	},

	beforeDestroy() {
		this.stopWaveAnimation();
	}
};
</script>

<style>
.container {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	background-color: #f5f5f5;
}

.remote-control {
	position: relative;
	width: 400rpx;
	height: 400rpx;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	/* background-color: #333; */
	border-radius: 50%;
	box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}

.control-btn {
	width: 90rpx;
	height: 90rpx;
	background-color: #f4f4f4;
	color: #007aff;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 28rpx;
	transition: all 0.2s;
	position: relative;
	box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}

.control-btn:active,
.control-btn.active {
	transform: scale(0.95);
	background-color: rgba(137, 207, 240, 0.3);
	color: white;
	box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

.up-btn {
	margin-bottom: 10px;
}

.down-btn {
	margin-top: 10px;
}

.middle-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
	padding: 20rpx;
}

.left-btn {
	margin-right: 10rpx;
	margin-left: 10rpx;
}

.right-btn {
	margin-right: 10rpx;
	margin-left: 10rpx;
}

.voice-btn {
	width: 120rpx;
	height: 120rpx;
	border-radius: 50%;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	background-color: #f4f4f4;
	color: #007aff;
	font-size: 30rpx;
	transition: all 0.2s;
	position: relative;
	overflow: hidden;
	box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}

.voice-btn:active,
.voice-btn.recording {
	background-color: #f44336;
	color: white;
	transform: scale(0.98);
}

.recording-text {
	font-size: 28rpx;
	margin-bottom: 4rpx;
}

.voice-wave {
	display: flex;
	align-items: flex-end;
	justify-content: center;
	height: 36rpx;
	margin-top: 4rpx;
}

.wave {
	width: 4px;
	background-color: white;
	margin: 0 2px;
	border-radius: 2px;
	transition: height 0.2s;
}

.voice-result {
	margin-top: 30px;
	padding: 15px;
	background-color: white;
	border-radius: 10px;
	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
	max-width: 80%;
	text-align: center;
}
</style>
